// 自测：1269购买矿石 -> 6008数量增加 -> 1060详情 -> 1068丢弃 -> 6008数量减少
const http = require('http');
const WebSocket = require('ws');

const CONFIG = {
    host: process.env.WS_HOST || 'localhost',
    port: parseInt(process.env.WS_PORT || process.env.HTTP_PORT || '3000', 10),
    mobile: process.env.TEST_USER_MOBILE || '17091279999',
    pwdHash: process.env.TEST_USER_PASSWORD_HASH || 'e10adc3949ba59abbe56e057f20f883e',
};

async function main() {
    console.log('\n🧪 开始【矿石购买/查看/丢弃】自测脚本...');
    const token = await loginOrRegister();
    const ws = await connectWs(token);
    await delay(200);
    await ensureCharacter(ws);

    // 读取商店矿石列表(1265)，选择一个矿石ID（尽量 1级矿，若无则取第一个矿）
    const shop = await sendAndWait(ws, 1265, { t: 2, pageNum: 0 });
    if (!Array.isArray(shop?.list) || shop.list.length === 0) {
        throw new Error('商店矿石列表为空');
    }
    const pickFrom = (arr, kw) => arr.find((x) => typeof x?.name === 'string' && x.name.includes(kw));
    let chosen = pickFrom(shop.list, '1级铁矿') || pickFrom(shop.list, '1级银矿') || pickFrom(shop.list, '1级金矿') || shop.list[0];
    const mineralId = Number(chosen.id);
    console.log(`🪨 选择矿石: ${chosen.name} (id=${mineralId})`);

    // 基线数量(6008)
    const beforeList = await sendAndWait(ws, 6008, { pageNum: 0 });
    const beforeNum = findCount(beforeList, mineralId);
    console.log(`📦 购买前数量: ${beforeNum}`);

    // 购买(1269)
    let buy = await sendAndWait(ws, 1269, { id: mineralId, count: 1, type: 0 });
    if (buy?.code !== 0) {
        console.log('💰 银币不足，尝试钱庄取银(1457) 以继续测试...');
        // 查询钱庄余额
        const balance = await sendAndWait(ws, 1450, {});
        const money = Number(balance?.data?.money || 0);
        // 尝试先向钱庄存入再取出：若普通银币不足则跳过存款，仅尝试取款
        try {
            if (money < 5000) {
                // 直接尝试从钱庄取2,000银
                try { await sendAndWait(ws, 1457, { num: 2000, pwd: '123456' }); } catch { }
            }
        } catch { }
        // 再次购买
        buy = await sendAndWait(ws, 1269, { id: mineralId, count: 1, type: 0 });
        if (buy?.code !== 0) throw new Error(`购买失败: ${buy?.msg || ''}`);
    }
    console.log('🛒 购买成功');

    // 再次查询(6008) 应为 before+1
    const afterBuyList = await sendAndWait(ws, 6008, { pageNum: 0 });
    const afterBuyNum = findCount(afterBuyList, mineralId);
    console.log(`📦 购买后数量: ${afterBuyNum}`);
    if (afterBuyNum !== beforeNum + 1) {
        throw new Error(`数量未增长: 期望 ${beforeNum + 1}, 实际 ${afterBuyNum}`);
    }

    // 详情(1060)
    const detail = await sendAndWait(ws, 1060, { gid: mineralId });
    if (detail?.code !== 0 || !Array.isArray(detail?.data)) {
        throw new Error('详情查询失败');
    }
    console.log('🔎 详情查询成功');

    // 丢弃(1068)
    const discard = await sendAndWait(ws, 1068, { gid: mineralId });
    if (discard?.code !== 0) throw new Error(`丢弃失败: ${discard?.msg || ''}`);
    console.log('🗑️ 丢弃成功');

    // 再次查询(6008) 应回到 before
    const afterDiscardList = await sendAndWait(ws, 6008, { pageNum: 0 });
    const afterDiscardNum = findCount(afterDiscardList, mineralId);
    console.log(`📦 丢弃后数量: ${afterDiscardNum}`);
    if (afterDiscardNum !== beforeNum) {
        throw new Error(`数量未回落: 期望 ${beforeNum}, 实际 ${afterDiscardNum}`);
    }

    console.log('✅ 矿石购买/详情/丢弃 全流程通过');
    try { ws.close(); } catch (_) { }
}

function findCount(resp, id) {
    const list = Array.isArray(resp?.list) ? resp.list : [];
    const row = list.find((x) => Number(x?.id) === Number(id));
    return Number(row?.num || 0);
}

function loginOrRegister() {
    return new Promise((resolve, reject) => {
        const req = http.request({ hostname: CONFIG.host, port: CONFIG.port, path: '/user-service/user/login', method: 'POST', headers: { 'Content-Type': 'application/json' } }, (res) => {
            let data = ''; res.on('data', (c) => data += c); res.on('end', () => {
                try {
                    const json = JSON.parse(data || '{}');
                    if (json.code === 0 && json.data?.accessToken) return resolve(json.data.accessToken);
                    registerUser().then(() => loginOnly().then(resolve).catch(reject)).catch(() => loginOnly().then(resolve).catch(reject));
                } catch { reject(new Error('登录响应解析失败')); }
            });
        }); req.on('error', reject); req.write(JSON.stringify({ mobile: CONFIG.mobile, pwd: CONFIG.pwdHash })); req.end();
    });
}
function loginOnly() {
    return new Promise((resolve, reject) => {
        const req = http.request({ hostname: CONFIG.host, port: CONFIG.port, path: '/user-service/user/login', method: 'POST', headers: { 'Content-Type': 'application/json' } }, (res) => {
            let data = ''; res.on('data', (c) => data += c); res.on('end', () => { try { const json = JSON.parse(data || '{}'); if (json.code === 0 && json.data?.accessToken) resolve(json.data.accessToken); else reject(new Error('登录失败')); } catch { reject(new Error('登录响应解析失败')); } });
        }); req.on('error', reject); req.write(JSON.stringify({ mobile: CONFIG.mobile, pwd: CONFIG.pwdHash })); req.end();
    });
}
function registerUser() {
    return new Promise((resolve) => {
        const req = http.request({ hostname: CONFIG.host, port: CONFIG.port, path: '/user-service/user/register', method: 'POST', headers: { 'Content-Type': 'application/json' } }, (res) => { res.on('data', () => { }); res.on('end', () => resolve(true)); }); req.on('error', () => resolve(true)); req.write(JSON.stringify({ mobile: CONFIG.mobile, pwd: CONFIG.pwdHash, captcha: '123456' })); req.end();
    });
}
function connectWs(token) { return new Promise((resolve, reject) => { const ws = new WebSocket(`ws://${CONFIG.host}:${CONFIG.port}/user-service/websocket?t=${token}`); ws.on('open', () => resolve(ws)); ws.on('error', reject); setTimeout(() => reject(new Error('WS连接超时')), 10000); }); }
async function ensureCharacter(ws) { const list = await waitAct(ws, 3, () => ws.send(JSON.stringify({ c: 3, d: null }))); const role = Array.isArray(list.roleList) && list.roleList[0]; if (!role) { await waitAct(ws, 5, () => ws.send(JSON.stringify({ c: 5, d: { name: '矿石测试', sex: 1, roleType: 1, headIndex: 2 } })), 15000); await delay(200); } const list2 = await waitAct(ws, 3, () => ws.send(JSON.stringify({ c: 3, d: null }))); const role2 = Array.isArray(list2.roleList) && list2.roleList[0]; if (!role2) throw new Error('无可用角色'); await waitAct(ws, 4, () => ws.send(JSON.stringify({ c: 4, d: { characterId: role2.id } }))); }
function sendAndWait(ws, actId, d) { return waitAct(ws, actId, () => ws.send(JSON.stringify({ c: actId, d: Object.keys(d || {}).length ? d : null }))); }
function waitAct(ws, actId, sendFn, timeoutMs = 10000) { return new Promise((resolve, reject) => { const handler = (raw) => { try { const msg = JSON.parse(raw.toString()); if (msg.act_id === actId) { ws.off('message', handler); clearTimeout(timer); resolve(msg); } } catch { } }; const timer = setTimeout(() => { ws.off('message', handler); reject(new Error(`等待 ${actId} 超时`)); }, timeoutMs); ws.on('message', handler); try { sendFn(); } catch (e) { ws.off('message', handler); clearTimeout(timer); reject(e); } }); }
function delay(ms) { return new Promise((r) => setTimeout(r, ms)); }

if (require.main === module) {
    main().catch((e) => { console.error('❌ 矿石流程自测失败:', e.message); process.exit(1); });
}


